package com.dana.friend.service.user.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.core.constants.CacheConstant;
import com.core.constants.Constants;
import com.core.constants.ExamListType;
import com.core.domain.TableDataInfo;
import com.core.enums.ResultCode;
import com.core.utils.ThreadLocalUtils;
import com.dana.friend.domain.exam.Exam;
import com.dana.friend.domain.exam.dto.QueryExamDTO;
import com.dana.friend.domain.exam.vo.ExamVO;
import com.dana.friend.domain.user.UserExam;
import com.dana.friend.manager.ExamCacheManager;
import com.dana.friend.mapper.exam.ExamMapper;
import com.dana.friend.mapper.user.UserExamMapper;
import com.dana.friend.service.user.IUserExamService;
import com.dana.security.exception.ServiceException;
import com.dana.security.service.TokenService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
@Slf4j
@Service
public class UserExamServiceImpl implements IUserExamService {


    @Value("${jwt.secret}")
    private String secret;

    @Autowired
    private ExamMapper examMapper;
    @Autowired
    private UserExamMapper userExamMapper;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private ExamCacheManager examCacheManager;

    /**
     * 用户竞赛报名
     * @param examId
     * @return
     */
    @Override
    public int enter(Long examId) {
        //校验是否满足报名条件

        //判断竞赛是否为空
        Exam exam = examMapper.selectById(examId);
        if (exam == null) {
            throw new ServiceException(ResultCode.EXAM_NOT_EXISTS);
        }
        //判断是否已经开始,开始了就不能报名
        if (exam.getStartTime().isBefore(LocalDateTime.now())) {
            throw new ServiceException(ResultCode.EXAM_IS_START);
        }
        //判断是否已经报名
        //Long userId=tokenService.getUserId(token,secret);
        Long userId = ThreadLocalUtils.get(Constants.USER_ID, Long.class);
        UserExam userExam = userExamMapper.selectOne(new LambdaQueryWrapper<UserExam>()
                .eq(UserExam::getExamId, examId)
                .eq(UserExam::getUserId, userId));
        if (userExam != null) {
            throw new ServiceException(ResultCode.USER_EXAM_IS_ENTER);
        }
        //将信息存储到redis
        examCacheManager.addUserExamCache(userId, examId);
        //将信息存储到数据库
        userExam = new UserExam();
        userExam.setExamId(examId);
        userExam.setUserId(userId);
        return userExamMapper.insert(userExam);
    }



    /**
     * 我的竞赛列表
     * @param queryExamDTO
     */
    @Override
    public TableDataInfo getList(QueryExamDTO queryExamDTO) {
        //第一次发布竞赛之后,redis中只有刚才发布的竞赛的信息,以前存储的已经发布的竞赛信息不会在redis中缓存
        //解决办法:去数据库中刷新缓存,将数据库中发布的竞赛信息也缓存到redis中
        log.info("当前线程:我的竞赛列表: {}", Thread.currentThread().getId());
        Long userId = ThreadLocalUtils.get(Constants.USER_ID, Long.class);
        //0-未完成的竞赛,1-历史竞赛,2-我的竞赛,直接设置返回的竞赛类型为我的竞赛
        queryExamDTO.setType(ExamListType.USER_EXAM_LIST.getValue());
        Long total = examCacheManager.getListSize(queryExamDTO.getType(), userId);
        List<ExamVO> examList;
        if (total == null || total <= 0) {
            //先去数据库查询,并且更新缓存
            PageHelper.startPage(queryExamDTO.getPageNum(), queryExamDTO.getPageSize());
            examList = userExamMapper.selectUserExamList(userId);
            //更新缓存
            examCacheManager.refreshCache(queryExamDTO.getType(), userId);
            total = new PageInfo<>(examList).getTotal();
        } else {
            examList = examCacheManager.getExamVOList(queryExamDTO, userId);
            total = examCacheManager.getListSize(queryExamDTO.getType(), userId);
        }
        if (CollectionUtil.isEmpty(examList)) {
            return TableDataInfo.empty();
        }
        return TableDataInfo.success(examList, total);
    }
}
